using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime;

namespace Microsoft.SharedSource.SqlServer.MDDE.Components
{
    [
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1705:LongAcronymsShouldBePascalCased"),
        SupportedComponentType("{DE50D3C7-41AF-4804-9247-CF1DEB147971}"),
    ]
    class MDDEDataFlowRowCountTransformation : MDDEDataFlowComponent
    {
        #region Member Variables

        private XmlNodeList changedProperties = null;
        private IDTSCustomPropertyCollection90 customProperties = null;

        IDTSComponentMetaData90 component = null;

        #endregion

        public MDDEDataFlowRowCountTransformation(Package package, Object component, string name, string uri)
            : base(package, component, name, uri)
        {
        }

        #region Overridden Methods

        public override void GetChangeXml(MDDEComponent subject, XmlDocument changeXml)
        {
            #region Set Values

            if (subject == null)
                throw new ArgumentNullException("Subject can not NULL");

            if (!(subject is MDDEDataFlowRowCountTransformation))
                throw new ArgumentException("Subject is not of type MDDEDataFlowRowCountTransformation");

            component = (IDTSComponentMetaData90)innerComponent;
            IDTSComponentMetaData90 referenceComponent = (IDTSComponentMetaData90)subject.InnerComponent;

            IDTSCustomPropertyCollection90 componentPropertyCollection = (IDTSCustomPropertyCollection90)component.CustomPropertyCollection;
            IDTSCustomPropertyCollection90 referenceComponentPropertyCollection = (IDTSCustomPropertyCollection90)referenceComponent.CustomPropertyCollection;

            XmlNode componentNode = null;
            componentNode = changeXml.CreateElement("Component");

            bool propertiesNodeEmpty = true;            

            #endregion

            #region Compare properties of Component with subject and create Properties' Xml

            for (int propertyIndex = 0; propertyIndex < componentPropertyCollection.Count; propertyIndex++)
            {
                if (componentPropertyCollection[propertyIndex].Name.CompareTo("Name") == 0)
                    continue;

                IDTSCustomProperty90 componentProperty = componentPropertyCollection[propertyIndex];
                IDTSCustomProperty90 referenceComponentProperty = referenceComponentPropertyCollection[propertyIndex];

                string componentPropertyValue = String.Empty;
                if (componentProperty.Value != null)
                    componentPropertyValue = componentProperty.Value.ToString();

                string referenceComponentPropertyValue = String.Empty;
                if (referenceComponentProperty.Value != null)
                    referenceComponentPropertyValue = referenceComponentProperty.Value.ToString();

                if (componentPropertyValue != referenceComponentPropertyValue)
                {
                    UpdateNodeProperties(changeXml, componentNode, componentProperty.Name, componentPropertyValue);
                    propertiesNodeEmpty = false;
                }
            }

            #endregion

            #region Update Changes Xml

            if (!propertiesNodeEmpty)
            {
                AddAttribute(changeXml, componentNode, "Name", this.name);
                AddAttribute(changeXml, componentNode, "URL", this.uri);
                AddAttribute(changeXml, componentNode, "RowsetDescriptor", "");

                changeXml.FirstChild.AppendChild(componentNode);
            }

            #endregion
        }

        public override bool ApplyChanges(XmlDocument changeXml, MDDEExecutionDAG originalPackage)
        {
            try
            {
                #region Set Values

                XmlNode componentChangeXml =
                    changeXml.SelectSingleNode("//PackageChanges/Component[@URL='" + this.uri + "']");

                //if (innerComponent == null)
                //    return false;

                //if (!(innerComponent is IDTSComponentMetaData90))
                //    return false;

                component = (IDTSComponentMetaData90)innerComponent;

                #endregion

                #region Read Change Xml

                if (componentChangeXml != null)
                {
                    if (!ReadChangeXml(componentChangeXml))
                        return false;
                }

                #endregion

                #region Apply Properties and Verify If Sufficient Property Values' Are Available

                if (!ApplyProperties())
                    return false;

                #endregion

                #region Reinitialize Component

                IDTSDesigntimeComponent90 designTimeComponent = component.Instantiate();

                designTimeComponent.AcquireConnections(null);

                DTSValidationStatus validationStatus = designTimeComponent.Validate();

                if (validationStatus == DTSValidationStatus.VS_ISBROKEN)
                {
                    designTimeComponent.ReleaseConnections();
                    return false;
                }

                designTimeComponent.ReinitializeMetaData();
                designTimeComponent.ReleaseConnections();

                #endregion

                return true;
            }

            catch
            {
                // TODO: Add to Log
                return false;
            }
        }

        public override bool Validate()
        {
            try
            {
                IDTSDesigntimeComponent90 designTimeComponent = ((IDTSComponentMetaData90)innerComponent).Instantiate();

                designTimeComponent.AcquireConnections(null);
                DTSValidationStatus validationStatus = designTimeComponent.Validate();
                designTimeComponent.ReleaseConnections();

                if (validationStatus == DTSValidationStatus.VS_ISVALID)
                    return true;
                else
                    return false;
            }

            catch
            {
                // TODO: Add to Log
                return false;
            }
        }

        #endregion

        #region Helper Methods

        private bool ReadChangeXml(XmlNode changeXml)
        {
            if (changeXml.SelectSingleNode("Properties") != null)
                changedProperties = changeXml["Properties"].ChildNodes;

            if (component.CustomPropertyCollection == null)
                return false;

            customProperties = (IDTSCustomPropertyCollection90)component.CustomPropertyCollection;

            if (customProperties == null)
                return false;            

            return true;
        }

        private bool ApplyProperties()
        {
            if (changedProperties != null)
            {
                foreach (XmlNode changedProperty in changedProperties)
                    customProperties[changedProperty.Attributes["Name"].Value].Value = this.ConvertToCompatibleType(changedProperty.Attributes["Value"].Value,
                        customProperties[changedProperty.Attributes["Name"].Value].Value.GetType().Name);
            }

            if (component.Instantiate().Validate()
                == DTSValidationStatus.VS_ISBROKEN)
                return false;
            else
                return true;
        }

        #endregion
    }
}
